package com.dsg.controller.apply;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSONObject;
import com.dsg.common.constants.DsgStatusConstant;
import com.dsg.common.util.SingletonLoginUtils;
import com.dsg.common.util.UUIDGenerator;
import com.dsg.common.util.toolbox.CollectionUtil;
import com.dsg.common.util.toolbox.StringUtil;
import com.dsg.entity.apply.DsgApplyCar;
import com.dsg.entity.apply.DsgApplyCard;
import com.dsg.entity.apply.DsgApplyStatus;
import com.dsg.entity.approve.DsgApproveCase;
import com.dsg.entity.model.apply.DsgApplyCarModel;
import com.dsg.service.apply.IDsgApplyCarService;
import com.dsg.service.apply.IDsgApplyStatusService;
import com.dsg.service.approve.IDsgApproveCaseService;
import com.dsg.support.LeveldbAccess;
import com.dsg.util.RRException;
import com.dsg.util.verify.VerifyHolder;
import com.dsg.util.verify.impl.NotEmptyVerify;
import com.dsg.workflow.WorkflowEngine;
import com.dsg.workflow.WorkflowService3;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @program: erp
 * @description:
 * @author: lironglai
 * @create: 2020-08-17 20:30
 */
@Slf4j
public class UploadDsgApplyCar extends AnalysisEventListener<DsgApplyCarModel> {

    private IDsgApplyCarService service;

    private IDsgApplyStatusService dsgApplyStatusService;

    private IDsgApproveCaseService caseService;

    private WorkflowEngine engine;

    private List<DsgApplyCar> list = new ArrayList<>();

    private List<String> errorList = new ArrayList();

    private VerifyHolder verifyHolder;

    private int totalSize = 1;

    private LeveldbAccess leveldbAccess;
    /**
     * 每隔2条存储数据库，实际使用中可以3000条，然后清理list ，方便内存回收
     */
    private static final int BATCH_COUNT = 3000;

    public UploadDsgApplyCar(IDsgApplyCarService service, IDsgApplyStatusService dsgApplyStatusService,
                             IDsgApproveCaseService caseService, WorkflowEngine engine, LeveldbAccess leveldbAccess) {
        this.service = service;
        this.dsgApplyStatusService = dsgApplyStatusService;
        this.caseService = caseService;
        this.engine = engine;
        this.leveldbAccess = leveldbAccess;
        //数据格式校验
        verifyHolder = new VerifyHolder(DsgApplyCarModel.class, errorList);
        verifyHolder.addVerify(new NotEmptyVerify());
    }

    /**
     * 这个每一条数据解析都会来调用  初始化 进来就要调用到的方法
     *
     * @param dsgApplyCarModel
     * @param analysisContext
     */
    @Override
    public void invoke(DsgApplyCarModel dsgApplyCarModel, AnalysisContext analysisContext) {
        log.info("解析到一条数据:{}", JSONObject.toJSON(dsgApplyCarModel));
        totalSize++;
        try {
            verifyHolder.check(dsgApplyCarModel, totalSize);
        } catch (Exception e) {
            log.error("檢驗數據異常:", e);
            throw new RRException("檢驗數據異常", e);
        }
        DsgApplyCar dsgApplyCar = new DsgApplyCar();
        BeanUtils.copyProperties(dsgApplyCarModel, dsgApplyCar);
        if (StringUtil.isNotEmpty(dsgApplyCarModel.getCheckStatus())) {
            switch (dsgApplyCarModel.getCheckStatus()) {
                case DsgStatusConstant.EXCEL_YES:
                    dsgApplyCar.setCheckStatus(DsgApplyStatus.AppStatus.success.getCode().intValue());
                    break;
                case DsgStatusConstant.EXCEL_NO:
                    dsgApplyCar.setCheckStatus(DsgApplyStatus.AppStatus.fail.getCode().intValue());
                    break;
            }
        }
        list.add(dsgApplyCar);
        // 达到BATCH_COUNT了，需要去存储一次数据库，防止数据几万条数据在内存，容易OOM
//        if (list.size() >= BATCH_COUNT) {
//            service.saveBatch(list);
        // 存储完成清理 list
//            list.clear();
//        }
    }

    /**
     * 所有数据解析完成了 都会来调用
     *
     * @param analysisContext
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        if (CollectionUtil.isNotEmpty(errorList)) {
            throw new RRException(errorList.toString());
        } else {
            List<String> keyList = new ArrayList<>();
            try {
                String oid = UUIDGenerator.getUUID();
                //查詢未處理數據並緩存
                DsgApplyCar dsgApplyCar = new DsgApplyCar();
                dsgApplyCar.setEntCode(SingletonLoginUtils.getSystemEntCode());
                dsgApplyCar.setCheckStatus(DsgApplyStatus.AppStatus.haveInHand.getCode());
                dsgApplyCar.setNodeName(WorkflowService3.NODE_CHECK_CAR_NO);
                dsgApplyCar.setUserId(SingletonLoginUtils.getSystemUserId());
                List<DsgApplyCar> dsgApplyCarList = service.selectDsgApplyCarList(dsgApplyCar);
                Map<String, List<DsgApplyCar>> dsgApplyCarMap = dsgApplyCarList.stream().collect(Collectors.groupingBy(I -> I.getOilComNo() + "-" + I.getCarNo()));
                for (String carKey : dsgApplyCarMap.keySet()) {
                    String key = leveldbAccess.genCacheKey(oid, DsgApplyCar.class.getSimpleName(), DsgApplyCard.class.getSimpleName(), carKey);
                    leveldbAccess.put(key, dsgApplyCarMap.get(carKey));
                    keyList.add(key);
                }
                dsgApplyCarList.clear();
                dsgApplyCarMap.clear();
                //回填數據狀態
                List<DsgApplyStatus> dsgApplyStatusList = new ArrayList<>();
                list.forEach(I -> {
                    String keyCar = leveldbAccess.genCacheKey(oid, DsgApplyCar.class.getSimpleName(), DsgApplyCard.class.getSimpleName(), I.getOilComNo(), I.getCarNo());
                    List<DsgApplyCar> dsgApplyCars = leveldbAccess.get(keyCar);
                    if (CollectionUtil.isNotEmpty(dsgApplyCars)) {
                        for (DsgApplyCar dac : dsgApplyCars) {
                            DsgApplyStatus dsgApplyStatus = new DsgApplyStatus();
                            dsgApplyStatus.setOid(dac.getStatusID());
                            dsgApplyStatus.setCheckStatus(I.getCheckStatus());
                            if (I.getCheckStatus().intValue() == DsgApplyStatus.AppStatus.success.getCode().intValue()) {
                                dsgApplyStatus.setIsCheck(DsgApplyStatus.AppStatus.yes.getCode());
                                DsgApproveCase approveCase = caseService.getCase(WorkflowService3.NODE_CHECK_CAR_NO, dac.getAppNo());
                                if (approveCase == null) {
                                    log.error(dac.getAppNo(), "對單CASE不存在");
                                    throw new RRException(String.format("%s對單CASE不存在", dac.getAppNo()));
                                } else {
                                    try {
                                        if (DsgApproveCase.Status.started.getCode().intValue() == approveCase.getStatus().intValue()) {
                                            engine.forward(approveCase);
                                        }
                                    } catch (Exception e) {
                                        log.error("推實例異常：", e);
                                        throw new RRException(dac.getAppNo() + e.getMessage());
                                    }
                                }
                            } else {
                                dsgApplyStatus.setIsCheck(DsgApplyStatus.AppStatus.no.getCode());
                            }
                            dsgApplyStatus.setCheckApprovalResult(I.getCheckApprovalResult());
                            dsgApplyStatus.setCheckLastTime(I.getCheckLastTime());
                            dsgApplyStatusList.add(dsgApplyStatus);
                        }
                    }
                });
                if (CollectionUtil.isNotEmpty(dsgApplyStatusList)) {
                    dsgApplyStatusService.updateBatchById(dsgApplyStatusList);
                    log.info(String.format("回填Check車牌數據%s條", dsgApplyStatusList.size()));
                } else {
                    log.info(String.format("無回填Check車牌數據"));
                    throw new RRException("無回填Check車牌數據");
                }
            } finally {
                if (CollectionUtil.isNotEmpty(keyList)) {
                    keyList.forEach(I -> {
                        leveldbAccess.delete(I);
                    });
                }
            }
        }
    }

}
